﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using System.Threading.Tasks;


namespace Bono.PhotoSorter
{
	public partial class MainForm : Form
	{
		//TODO:  Should handle other image file formats than just jpegs... not sure how exif data is stored for others
		//TODO:  ****  Multithread the application  *****  DONE!
		//TODO:  Implement proper progress reporting  DONE!
		//TODO:  Properly comment code
		//TODO:  Implement a way to cancel/abort the application (closely tied to multithreading the application)  DONE!
		//TODO:  Store application settings on close and initialize when reopened... or at least allow that option... DONE!
		//TODO:  Should probably just queue up conflicts and prompt user at the end of the process, rather than as they happen. PROBABLY WON'T DO

		#region Variables

		private string _sourceRoot;
		private string _targetRoot;
		private string _backupRoot;
		private bool _removeEmptyFolders;
		private bool _createBackup;
		private Constants.FileAction _action;
		private List<FileListItem> _sourceFilesList;
		private Constants.ResolveConflictAction _applyAllResolveAction;
		private long _startTicks;
		private long _stopTicks;
		private bool _recursive;
		private SearchOption _searchOption;

		#endregion

		#region Properties



		private string SourceRoot
		{
			get
			{
				return _sourceRoot;
			}
			set
			{
				SourceFolderTextBox.Text = value;
				_sourceRoot = value;
			}
		}

		private string TargetRoot
		{
			get
			{
				return _targetRoot;
			}
			set
			{
				TargetFolderTextBox.Text = value;
				_targetRoot = value;
			}
		}

		private string BackupRoot
		{
			get
			{
				return _backupRoot;
			}
			set
			{
				BackupFolderTextBox.Text = value;
				_backupRoot = value;
			}
		}

		private bool RemoveEmptyFolders
		{
			get
			{
				return _removeEmptyFolders;
			}
			set
			{
				DeleteEmptyFoldersCheckBox.Checked = value;
				_removeEmptyFolders = value;
			}
		}

		private bool Recursive
		{
			get
			{
				return _recursive;
			}
			set
			{
				RecursiveCheckBox.Checked = value;
				_recursive = value;
				if (value)
				{
					_searchOption = SearchOption.AllDirectories;
				}
				else
				{
					_searchOption = SearchOption.TopDirectoryOnly;
				}
			}
		}


		private Constants.FileAction FileAction
		{
			get
			{
				return _action;
			}
			set
			{
				if(value == Constants.FileAction.Copy)
				{
					CopyRadioButton.Checked = true;
				}
				else if (value == Constants.FileAction.Move)
				{
					MoveRadioButton.Checked = true;
				}
				else
				{
					DoNothingRadioButton.Checked = true;
				}
				_action = value;
			}
		}

		private bool CreateBackup
		{
			get
			{
				return _createBackup;
			}
			set
			{
				BackupFilesCheckBox.Checked = value;
				_createBackup = value;
			}
		}

		private Constants.ResolveConflictAction ApplyAllResolveAction
		{
			get
			{
				return _applyAllResolveAction;
			}
			set
			{
				_applyAllResolveAction = value;
			}
		}

		#endregion

		#region Constructor(s)
		public MainForm()
		{
			InitializeComponent();
			ApplyAllResolveAction = Constants.ResolveConflictAction.Unset;
		}
		#endregion
		
		#region Private Methods

		private bool ValidateInputs()
		{
			//Check Source Directory
			if(String.IsNullOrEmpty(SourceRoot) || Directory.Exists(SourceRoot) == false)
			{
				throw new DirectoryNotFoundException("You must specify a valid source directory from which to read.");
			}

			//Check Target Directory
			if (String.IsNullOrEmpty(TargetRoot))
			{
				throw new DirectoryNotFoundException("You must specify a valid target directory for writing files.");
			}

			//If the target directory doesn't exist, create it.
			if (Directory.Exists(TargetRoot) == false)
			{
				Directory.CreateDirectory(TargetRoot);
			}

			//Ensure that the source and target are not the same
			if(String.Compare(SourceRoot, TargetRoot, true) == 0)
			{
				throw new Exception("The source directory and target directory cannot be the same.");
			}

			//Ensure that the source directory and backup directories are not the same.
			if (CreateBackup && (String.Compare(SourceRoot, BackupRoot, true) == 0))
			{
				throw new Exception("The source directory and backup directory cannot be the same.");
			}
			
			return true;
		}
		
		private void SetOptions()
		{
			TargetRoot = TargetFolderTextBox.Text;
			SourceRoot = SourceFolderTextBox.Text;
			RemoveEmptyFolders = DeleteEmptyFoldersCheckBox.Checked;
			CreateBackup = BackupFilesCheckBox.Checked;
			BackupRoot = BackupFolderTextBox.Text;
			_sourceFilesList = new List<FileListItem>();

			if(CopyRadioButton.Checked)
			{
				FileAction = Constants.FileAction.Copy;
			}
			else if(MoveRadioButton.Checked)
			{
				FileAction = Constants.FileAction.Move;
			}
			else
			{
				FileAction = Constants.FileAction.DoNothing;
			}
		}
		
		private void SaveUiOptions()
		{
			Properties.Settings.Default.BackupDirectory = BackupRoot;
			Properties.Settings.Default.CreateBackup = CreateBackup;
			Properties.Settings.Default.CopyMoveOption = (int)FileAction;
			Properties.Settings.Default.RemoveEmptyFolders = RemoveEmptyFolders;
			Properties.Settings.Default.SourceDirectory = SourceRoot;
			Properties.Settings.Default.TargetDirectory = TargetRoot;
			Properties.Settings.Default.Recursive = Recursive;
			Properties.Settings.Default.Save();
		}

		private void LoadUiOptions()
		{
			BackupRoot = Properties.Settings.Default.BackupDirectory;
			CreateBackup = Properties.Settings.Default.CreateBackup;
			FileAction = (Constants.FileAction)Properties.Settings.Default.CopyMoveOption;
			RemoveEmptyFolders = Properties.Settings.Default.RemoveEmptyFolders;
			SourceRoot = Properties.Settings.Default.SourceDirectory;
			TargetRoot = Properties.Settings.Default.TargetDirectory;
			Recursive = Properties.Settings.Default.Recursive;
		}

		private void AttemptAbort()
		{
			if (fileWorker != null && fileWorker.IsBusy)
			{
				fileWorker.CancelAsync();
			}
		}

		#endregion
		
		#region Event Handlers
		
		private void fileWorker_DoWork(object sender, DoWorkEventArgs e)
		{
			Processing.ProcessFiles(_sourceFilesList, FileAction, e, fileWorker);
		}

		private void fileWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			FileProcessStatus status = e.UserState as FileProcessStatus;
			if(status != null)
			{
				StatusValueLabel.Text =
					String.Format("{0} of {1} files, {2} conflict(s) found", status.CurrentFile, status.TotalFiles, status.ConflictCount);
				statusStrip1.Refresh();

				FilesListView.Items.Add(
					new ListViewItem(new[]
					                 	{
					                 		status.CurrentListItem.SourceFilePath,
					                 		status.CurrentListItem.DateTaken.ToString(Constants.DateFormat),
					                 		status.CurrentListItem.TargetFilePath
					                 	}));

				FilesListView.EnsureVisible(status.CurrentFile-1);
			}

			FileProcessProgress.Value = e.ProgressPercentage;
			
			FileProcessProgress.Refresh();

			
		}

		private void fileWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			//Cleanup empty folders if necessary
			if (RemoveEmptyFolders && FileAction == Constants.FileAction.Move)
			{
				StatusValueLabel.Text = "Deleting empty folders...";
				statusStrip1.Refresh();
				Processing.CleanupFolders(SourceRoot);
			}

			AbortButton.Enabled = false;

			_stopTicks = DateTime.Now.Ticks;
			double time = (double)(_stopTicks - _startTicks) / (double)TimeSpan.TicksPerSecond;
			MessageBox.Show(time.ToString("#0.000000") + @" seconds");
		}

		private void PhotoSorter_FormClosing(object sender, FormClosingEventArgs e)
		{
			SaveUiOptions();
		}

		private void BrowseSourceButton_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog browse = new FolderBrowserDialog();
			if (Directory.Exists(SourceRoot))
			{
				browse.SelectedPath = SourceRoot;
			}

			if (browse.ShowDialog() == DialogResult.OK)
			{
				SourceFolderTextBox.Text = browse.SelectedPath;
				SourceRoot = browse.SelectedPath;
			}
		}

		private void BrowseTargetButton_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog browse = new FolderBrowserDialog();
			if (Directory.Exists(TargetRoot))
			{
				browse.SelectedPath = TargetRoot;
			}

			if (browse.ShowDialog() == DialogResult.OK)
			{
				TargetFolderTextBox.Text = browse.SelectedPath;
				TargetRoot = browse.SelectedPath;
			}
		}

		private void BrowseBackupButton_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog browse = new FolderBrowserDialog();
			if (Directory.Exists(BackupRoot))
			{
				browse.SelectedPath = BackupRoot;
			}

			if (browse.ShowDialog() == DialogResult.OK)
			{
				BackupFolderTextBox.Text = browse.SelectedPath;
				BackupRoot = browse.SelectedPath;
			}
		}

		private void ExecuteButton_Click(object sender, EventArgs e)
		{
			FileProcessProgress.Value = 0;

			try
			{
				_startTicks = DateTime.Now.Ticks;

				SetOptions();

				if (ValidateInputs())
				{
					AbortButton.Enabled = true;

					//Clear out old files if needed
					FilesListView.Items.Clear();

					//Build the file list
					StatusValueLabel.Text = "Building list of items to process...";
					statusStrip1.Refresh();
					_sourceFilesList = Processing.BuildFileListItems(SourceRoot, TargetRoot, _searchOption);

					//Backup Files
					if (CreateBackup)
					{
						StatusValueLabel.Text = "Backing up source folder...";
						statusStrip1.Refresh();
						Processing.CopyFolder(SourceRoot, BackupRoot, true, "*.jpg");
					}

					//Process files
					if(FileAction == Constants.FileAction.DoNothing)
					{
						FileProcessProgress.Value = 100;
					}
					else
					{
						StatusValueLabel.Text = "Beginning processing...";
						statusStrip1.Refresh();
						fileWorker.RunWorkerAsync();
					}

				}

				
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.GetType() + Environment.NewLine + ex.Message, @"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		
		private void PhotoSorter_Load(object sender, EventArgs e)
		{
			LoadUiOptions();
		}
	
		private void SourceFolderTextBox_Leave(object sender, EventArgs e)
		{
			SourceRoot = SourceFolderTextBox.Text;
		}

		private void TargetFolderTextBox_Leave(object sender, EventArgs e)
		{
			TargetRoot = TargetFolderTextBox.Text;
		}

		private void BackupFolderTextBox_Leave(object sender, EventArgs e)
		{
			BackupRoot = BackupFolderTextBox.Text;
		}

		private void DoNothingRadioButton_CheckedChanged(object sender, EventArgs e)
		{
			if(((RadioButton)sender).Checked)
			{
				FileAction = Constants.FileAction.DoNothing;
			}
		}

		private void CopyRadioButton_CheckedChanged(object sender, EventArgs e)
		{
			if (((RadioButton)sender).Checked)
			{
				FileAction = Constants.FileAction.Copy;
			}
		}

		private void MoveRadioButton_CheckedChanged(object sender, EventArgs e)
		{
			if (((RadioButton)sender).Checked)
			{
				FileAction = Constants.FileAction.Move;
			}
		}

		private void DeleteEmptyFoldersCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			RemoveEmptyFolders = DeleteEmptyFoldersCheckBox.Checked;
		}

		private void RecursiveCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			Recursive = RecursiveCheckBox.Checked;
		}



		private void BackupFilesCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			CreateBackup = BackupFilesCheckBox.Checked;
		}
		
		private void AbortButton_Click(object sender, EventArgs e)
		{
			AttemptAbort();
		}

		private void ExitButton_Click(object sender, EventArgs e)
		{
			AttemptAbort();
			SaveUiOptions();
			Application.Exit();
		}

	

		#endregion






		
	}
}